﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DirectPOS.BarCodeScanner {
  public class InlineKey {
    // Scan Mambers
    Key mLastUp = Key.None;
    bool mScanning = false;
    StringBuilder mScanData = new StringBuilder();
    KeyConverter mScanKeyConverter = new KeyConverter();

    public Action<char, string> ScannedCode;
    public Action<Int64> ScannedEAN;
    public Action<string> ScannedCode128;
    
    List<Key> mKeyDebugLog = new List<Key>();

    public InlineKey(ContentControl aWindow) {
      aWindow.PreviewKeyDown += new KeyEventHandler(BaseWindow_PreviewKeyDown);
      aWindow.PreviewKeyUp += new KeyEventHandler(BaseWindow_PreviewKeyUp);
    }

    void BaseWindow_PreviewKeyUp(object sender, KeyEventArgs e) {
      // Yes I know the if blocks could be conslidated, but its easier to read
      // the logic this way and expand it as necessary.
      //
      // Note: This looks for ALL Ctrl-B combos, including Ctrl-Alt-B, Ctrl-Shift-B, etc.
      // For my initial needs this is fine, but probably should be upgraded
      // to respond to only Ctrl-B
      //
      // Note also that we only look for LeftCtrl, other scanners
      // could possibly use RightCtrl but I think not. The scanner is actaully sending
      // 0x02, but WPF is likely the one interpreting it as Ctrl-B according to old keyboard semantics.

      if (mScanning) {
        // Handle all Keyups while scanning to prevent other events from catching them
        e.Handled = true;

        // ETX
        if (mLastUp == Key.LeftCtrl && e.Key == Key.C) {
          // Ctrl comes up before the C, so we have to track it
          //
          // Handle this in key up, otherwise mScanning would be set to false in KeyDown
          // and then the C-Up would be passed on and seen by other external events.
          //
          // Note: This also leaks the ctrl-up, without a down, but we live with that for now.
          mScanning = false;
          ScanReceived(mScanData.ToString());
        }
      }
      mLastUp = e.Key;
    }

    void ScanReceived(string aData) {
      char xPrefix = aData[0];

      // b: UPC-A
      // e: EAN-13
      if (xPrefix == 'b' || xPrefix == 'e') {
        if (ScannedEAN != null) {
          ScannedEAN(Int64.Parse(aData.Substring(1)));
        }
      }

      // g: Code128
      if (xPrefix == 'g') {
        if (ScannedCode128 != null) {
          ScannedCode128(aData.Substring(1));
        }
      }

      if (ScannedCode != null) {
        // TODO: In future use enum instead of the char for type
        ScannedCode(aData[0], aData.Substring(1));
      }
    }

    void BaseWindow_PreviewKeyDown(object sender, KeyEventArgs e) {
      if (mScanning) {
        // Handle all Keydowns while scanning to preven other events from catching them
        e.Handled = true;
        // OK if shift key down, but we dont want to process it if it is the shift key...
        if ((Keyboard.Modifiers == ModifierKeys.None || Keyboard.Modifiers == ModifierKeys.Shift) && e.Key != Key.LeftShift && e.Key != Key.RightShift) {
          mKeyDebugLog.Add(e.Key);
          string xChar;
          if (e.Key == System.Windows.Input.Key.OemMinus) {
            // We have to do this manually. On my system ConvertToString makes
            // it a 6, but on POS-PC it spells it out to OemMinus.... Both are
            // Windows 7 but something is different about my PC.
            xChar = "-";
          } else {
            xChar = mScanKeyConverter.ConvertToString(e.Key);
          }
          if (Keyboard.Modifiers == ModifierKeys.None) {
            xChar = xChar.ToLower();
          }
          mScanData.Append(xChar);
        }
      } else {
        // STX
        if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.B) {
          mScanning = true;
          mScanData.Clear();
          mKeyDebugLog.Clear();
        }
      }
    }
  }
}
